Clover icon

compiler

  1. Project Clover database Thu Jan 12 2023 14:04:05 MST
  2. Package com.google.javascript.rhino

File Node.java

 

Coverage histogram

../../../../img/srcFileCovDistChart9.png
50% of files have more coverage

Code metrics

250
776
253
12
2,380
1,594
416
0.54
3.07
21.08
1.64

Classes

Class Line # Actions
Node 63 680 352 187
0.8310749583.1%
Node.NumberNode 142 13 7 3
0.863636486.4%
Node.StringNode 183 15 10 6
0.7857142778.6%
Node.PropListItem 253 0 0 0
-1.0 -
Node.AbstractPropListItem 261 4 3 0
1.0100%
Node.ObjectPropListItem 288 6 6 3
0.769230876.9%
Node.IntPropListItem 321 6 5 2
0.818181881.8%
Node.SiblingNodeIterable 1246 14 7 6
0.7391304473.9%
Node.AncestorIterable 1332 9 6 4
0.7575%
Node.FileLevelJsDocBuilder 1828 8 3 0
1.0100%
Node.SideEffectFlags 2009 14 13 4
0.851851985.2%
Node.NodeMismatch 2122 7 4 4
0.666666766.7%
 

Contributing tests

This file is covered by 2233 tests. .

Source view

1    /*
2    *
3    * ***** BEGIN LICENSE BLOCK *****
4    * Version: MPL 1.1/GPL 2.0
5    *
6    * The contents of this file are subject to the Mozilla Public License Version
7    * 1.1 (the "License"); you may not use this file except in compliance with
8    * the License. You may obtain a copy of the License at
9    * http://www.mozilla.org/MPL/
10    *
11    * Software distributed under the License is distributed on an "AS IS" basis,
12    * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
13    * for the specific language governing rights and limitations under the
14    * License.
15    *
16    * The Original Code is Rhino code, released
17    * May 6, 1999.
18    *
19    * The Initial Developer of the Original Code is
20    * Netscape Communications Corporation.
21    * Portions created by the Initial Developer are Copyright (C) 1997-1999
22    * the Initial Developer. All Rights Reserved.
23    *
24    * Contributor(s):
25    * Norris Boyd
26    * Roger Lawrence
27    * Mike McCabe
28    *
29    * Alternatively, the contents of this file may be used under the terms of
30    * the GNU General Public License Version 2 or later (the "GPL"), in which
31    * case the provisions of the GPL are applicable instead of those above. If
32    * you wish to allow use of your version of this file only under the terms of
33    * the GPL and not to allow others to use your version of this file under the
34    * MPL, indicate your decision by deleting the provisions above and replacing
35    * them with the notice and other provisions required by the GPL. If you do
36    * not delete the provisions above, a recipient may use your version of this
37    * file under either the MPL or the GPL.
38    *
39    * ***** END LICENSE BLOCK ***** */
40   
41    package com.google.javascript.rhino;
42   
43    import com.google.common.annotations.VisibleForTesting;
44    import com.google.common.base.Objects;
45    import com.google.common.base.Preconditions;
46    import com.google.javascript.rhino.jstype.JSType;
47    import com.google.javascript.rhino.jstype.SimpleSourceFile;
48    import com.google.javascript.rhino.jstype.StaticSourceFile;
49   
50    import java.io.IOException;
51    import java.io.Serializable;
52    import java.util.Arrays;
53    import java.util.Collections;
54    import java.util.Iterator;
55    import java.util.NoSuchElementException;
56    import java.util.Set;
57   
58    /**
59    * This class implements the root of the intermediate representation.
60    *
61    */
62   
 
63    public class Node implements Cloneable, Serializable {
64   
65    private static final long serialVersionUID = 1L;
66   
67    public static final int
68    JSDOC_INFO_PROP = 29, // contains a TokenStream.JSDocInfo object
69    VAR_ARGS_NAME = 30, // the name node is a variable length
70    // argument placeholder.
71    INCRDECR_PROP = 32, // pre or post type of increment/decrement
72    QUOTED_PROP = 36, // set to indicate a quoted object lit key
73    OPT_ARG_NAME = 37, // The name node is an optional argument.
74    SYNTHETIC_BLOCK_PROP = 38, // A synthetic block. Used to make
75    // processing simpler, and does not
76    // represent a real block in the source.
77    EMPTY_BLOCK = 39, // Used to indicate BLOCK that replaced
78    // EMPTY nodes.
79    ORIGINALNAME_PROP = 40, // The original name of the node, before
80    // renaming.
81    SIDE_EFFECT_FLAGS = 42, // Function or constructor call side effect
82    // flags
83    // Coding convention props
84    IS_CONSTANT_NAME = 43, // The variable or property is constant.
85    IS_NAMESPACE = 46, // The variable creates a namespace.
86    IS_DISPATCHER = 47, // The function is a dispatcher function,
87    // probably generated from Java code, and
88    // should be resolved to the proper
89    // overload if possible.
90    DIRECTIVES = 48, // The ES5 directives on this node.
91    DIRECT_EVAL = 49, // ES5 distinguishes between direct and
92    // indirect calls to eval.
93    FREE_CALL = 50, // A CALL without an explicit "this" value.
94    STATIC_SOURCE_FILE = 51, // A StaticSourceFile indicating the file
95    // where this node lives.
96    LENGTH = 52, // The length of the code represented by
97    // this node.
98    INPUT_ID = 53, // The id of the input associated with this
99    // node.
100    SLASH_V = 54, // Whether a STRING node contains a \v
101    // vertical tab escape. This is a total hack.
102    // See comments in IRFactory about this.
103    INFERRED_FUNCTION = 55, // Marks a function whose parameter types
104    // have been inferred.
105    LAST_PROP = 55;
106   
107    public static final int // flags for INCRDECR_PROP
108    DECR_FLAG = 0x1,
109    POST_FLAG = 0x2;
110   
 
111  339 toggle private static final String propToString(int propType) {
112  339 switch (propType) {
113  0 case VAR_ARGS_NAME: return "var_args_name";
114   
115  2 case JSDOC_INFO_PROP: return "jsdoc_info";
116   
117  1 case INCRDECR_PROP: return "incrdecr";
118  3 case QUOTED_PROP: return "quoted";
119  0 case OPT_ARG_NAME: return "opt_arg";
120   
121  16 case SYNTHETIC_BLOCK_PROP: return "synthetic";
122  0 case EMPTY_BLOCK: return "empty_block";
123  0 case ORIGINALNAME_PROP: return "originalname";
124  0 case SIDE_EFFECT_FLAGS: return "side_effect_flags";
125   
126  0 case IS_CONSTANT_NAME: return "is_constant_name";
127  0 case IS_NAMESPACE: return "is_namespace";
128  0 case IS_DISPATCHER: return "is_dispatcher";
129  0 case DIRECTIVES: return "directives";
130  0 case DIRECT_EVAL: return "direct_eval";
131  3 case FREE_CALL: return "free_call";
132  233 case STATIC_SOURCE_FILE: return "source_file";
133  11 case INPUT_ID: return "input_id";
134  68 case LENGTH: return "length";
135  0 case SLASH_V: return "slash_v";
136  0 case INFERRED_FUNCTION: return "inferred";
137  0 default:
138  0 throw new IllegalStateException("unexpect prop id " + propType);
139    }
140    }
141   
 
142    private static class NumberNode extends Node {
143   
144    private static final long serialVersionUID = 1L;
145   
 
146  27354 toggle NumberNode(double number) {
147  27354 super(Token.NUMBER);
148  27354 this.number = number;
149    }
150   
 
151  0 toggle public NumberNode(double number, int lineno, int charno) {
152  0 super(Token.NUMBER, lineno, charno);
153  0 this.number = number;
154    }
155   
 
156  60556 toggle @Override
157    public double getDouble() {
158  60556 return this.number;
159    }
160   
 
161  139 toggle @Override
162    public void setDouble(double d) {
163  139 this.number = d;
164    }
165   
 
166  10133 toggle @Override
167    boolean isEquivalentTo(Node node, boolean compareJsType, boolean recurse) {
168  10133 boolean equivalent = super.isEquivalentTo(node, compareJsType, recurse);
169  10133 if (equivalent) {
170  8104 double thisValue = getDouble();
171  8104 double thatValue = ((NumberNode) node).getDouble();
172  8104 if (thisValue == thatValue) {
173    // detect the difference between 0.0 and -0.0.
174  8037 return (thisValue != 0.0) || (1/thisValue == 1/thatValue);
175    }
176    }
177  2096 return false;
178    }
179   
180    private double number;
181    }
182   
 
183    private static class StringNode extends Node {
184   
185    private static final long serialVersionUID = 1L;
186   
 
187  781094 toggle StringNode(int type, String str) {
188  781094 super(type);
189  781094 if (null == str) {
190  0 throw new IllegalArgumentException("StringNode: str is null");
191    }
192  781094 this.str = str;
193    }
194   
 
195  8762 toggle StringNode(int type, String str, int lineno, int charno) {
196  8762 super(type, lineno, charno);
197  8762 if (null == str) {
198  0 throw new IllegalArgumentException("StringNode: str is null");
199    }
200  8762 this.str = str;
201    }
202   
203    /**
204    * returns the string content.
205    * @return non null.
206    */
 
207  1009449 toggle @Override
208    public String getString() {
209  1009449 return this.str;
210    }
211   
212    /**
213    * sets the string content.
214    * @param str the new value. Non null.
215    */
 
216  5368 toggle @Override
217    public void setString(String str) {
218  5368 if (null == str) {
219  0 throw new IllegalArgumentException("StringNode: str is null");
220    }
221  5368 this.str = str;
222    }
223   
 
224  75406 toggle @Override
225    boolean isEquivalentTo(Node node, boolean compareJsType, boolean recurse) {
226  75406 return (super.isEquivalentTo(node, compareJsType, recurse)
227    && this.str.equals(((StringNode) node).str));
228    }
229   
230    /**
231    * If the property is not defined, this was not a quoted key. The
232    * QUOTED_PROP int property is only assigned to STRING tokens used as
233    * object lit keys.
234    * @return true if this was a quoted string key in an object literal.
235    */
 
236  2582 toggle @Override
237    public boolean isQuotedString() {
238  2582 return getBooleanProp(QUOTED_PROP);
239    }
240   
241    /**
242    * This should only be called for STRING nodes created in object lits.
243    */
 
244  7 toggle @Override
245    public void setQuotedString() {
246  7 putBooleanProp(QUOTED_PROP, true);
247    }
248   
249    private String str;
250    }
251   
252    // PropListItems must be immutable so that they can be shared.
 
253    private interface PropListItem {
254    int getType();
255    PropListItem getNext();
256    PropListItem chain(PropListItem next);
257    Object getObjectValue();
258    int getIntValue();
259    }
260   
 
261    private static abstract class AbstractPropListItem
262    implements PropListItem, Serializable {
263    private static final long serialVersionUID = 1L;
264   
265    private final PropListItem next;
266    private final int propType;
267   
 
268  928203 toggle AbstractPropListItem(int propType, PropListItem next) {
269  928203 this.propType = propType;
270  928203 this.next = next;
271    }
272   
 
273  1628776 toggle @Override
274    public int getType() {
275  1628776 return propType;
276    }
277   
 
278  1191207 toggle @Override
279    public PropListItem getNext() {
280  1191207 return next;
281    }
282   
283    @Override
284    public abstract PropListItem chain(PropListItem next);
285    }
286   
287    // A base class for Object storing props
 
288    private static class ObjectPropListItem
289    extends AbstractPropListItem {
290    private static final long serialVersionUID = 1L;
291   
292    private final Object objectValue;
293   
 
294  131034 toggle ObjectPropListItem(int propType, Object objectValue, PropListItem next) {
295  131034 super(propType, next);
296  131034 this.objectValue = objectValue;
297    }
298   
 
299  0 toggle @Override
300    public int getIntValue() {
301  0 throw new UnsupportedOperationException();
302    }
303   
 
304  499257 toggle @Override
305    public Object getObjectValue() {
306  499257 return objectValue;
307    }
308   
 
309  248 toggle @Override
310    public String toString() {
311  248 return objectValue == null ? "null" : objectValue.toString();
312    }
313   
 
314  157 toggle @Override
315    public PropListItem chain(PropListItem next) {
316  157 return new ObjectPropListItem(getType(), objectValue, next);
317    }
318    }
319   
320    // A base class for int storing props
 
321    private static class IntPropListItem extends AbstractPropListItem {
322    private static final long serialVersionUID = 1L;
323   
324    final int intValue;
325   
 
326  797169 toggle IntPropListItem(int propType, int intValue, PropListItem next) {
327  797169 super(propType, next);
328  797169 this.intValue = intValue;
329    }
330   
 
331  70377 toggle @Override
332    public int getIntValue() {
333  70377 return intValue;
334    }
335   
 
336  0 toggle @Override
337    public Object getObjectValue() {
338  0 throw new UnsupportedOperationException();
339    }
340   
 
341  91 toggle @Override
342    public String toString() {
343  91 return String.valueOf(intValue);
344    }
345   
 
346  29565 toggle @Override
347    public PropListItem chain(PropListItem next) {
348  29565 return new IntPropListItem(getType(), intValue, next);
349    }
350    }
351   
 
352  1650204 toggle public Node(int nodeType) {
353  1650204 type = nodeType;
354  1650204 parent = null;
355  1650204 sourcePosition = -1;
356    }
357   
 
358  33441 toggle public Node(int nodeType, Node child) {
359  33441 Preconditions.checkArgument(child.parent == null,
360    "new child has existing parent");
361  33441 Preconditions.checkArgument(child.next == null,
362    "new child has existing sibling");
363   
364  33441 type = nodeType;
365  33441 parent = null;
366  33441 first = last = child;
367  33441 child.next = null;
368  33441 child.parent = this;
369  33441 sourcePosition = -1;
370    }
371   
 
372  51204 toggle public Node(int nodeType, Node left, Node right) {
373  51204 Preconditions.checkArgument(left.parent == null,
374    "first new child has existing parent");
375  51204 Preconditions.checkArgument(left.next == null,
376    "first new child has existing sibling");
377  51204 Preconditions.checkArgument(right.parent == null,
378    "second new child has existing parent");
379  51204 Preconditions.checkArgument(right.next == null,
380    "second new child has existing sibling");
381  51204 type = nodeType;
382  51204 parent = null;
383  51204 first = left;
384  51204 last = right;
385  51204 left.next = right;
386  51204 left.parent = this;
387  51204 right.next = null;
388  51204 right.parent = this;
389  51204 sourcePosition = -1;
390    }
391   
 
392  942 toggle public Node(int nodeType, Node left, Node mid, Node right) {
393  942 Preconditions.checkArgument(left.parent == null);
394  942 Preconditions.checkArgument(left.next == null);
395  942 Preconditions.checkArgument(mid.parent == null);
396  942 Preconditions.checkArgument(mid.next == null);
397  942 Preconditions.checkArgument(right.parent == null);
398  942 Preconditions.checkArgument(right.next == null);
399  942 type = nodeType;
400  942 parent = null;
401  942 first = left;
402  942 last = right;
403  942 left.next = mid;
404  942 left.parent = this;
405  942 mid.next = right;
406  942 mid.parent = this;
407  942 right.next = null;
408  942 right.parent = this;
409  942 sourcePosition = -1;
410    }
411   
 
412  0 toggle public Node(int nodeType, Node left, Node mid, Node mid2, Node right) {
413  0 Preconditions.checkArgument(left.parent == null);
414  0 Preconditions.checkArgument(left.next == null);
415  0 Preconditions.checkArgument(mid.parent == null);
416  0 Preconditions.checkArgument(mid.next == null);
417  0 Preconditions.checkArgument(mid2.parent == null);
418  0 Preconditions.checkArgument(mid2.next == null);
419  0 Preconditions.checkArgument(right.parent == null);
420  0 Preconditions.checkArgument(right.next == null);
421  0 type = nodeType;
422  0 parent = null;
423  0 first = left;
424  0 last = right;
425  0 left.next = mid;
426  0 left.parent = this;
427  0 mid.next = mid2;
428  0 mid.parent = this;
429  0 mid2.next = right;
430  0 mid2.parent = this;
431  0 right.next = null;
432  0 right.parent = this;
433  0 sourcePosition = -1;
434    }
435   
 
436  12680 toggle public Node(int nodeType, int lineno, int charno) {
437  12680 type = nodeType;
438  12680 parent = null;
439  12680 sourcePosition = mergeLineCharNo(lineno, charno);
440    }
441   
 
442  4963 toggle public Node(int nodeType, Node child, int lineno, int charno) {
443  4963 this(nodeType, child);
444  4963 sourcePosition = mergeLineCharNo(lineno, charno);
445    }
446   
 
447  0 toggle public Node(int nodeType, Node left, Node right, int lineno, int charno) {
448  0 this(nodeType, left, right);
449  0 sourcePosition = mergeLineCharNo(lineno, charno);
450    }
451   
 
452  0 toggle public Node(int nodeType, Node left, Node mid, Node right,
453    int lineno, int charno) {
454  0 this(nodeType, left, mid, right);
455  0 sourcePosition = mergeLineCharNo(lineno, charno);
456    }
457   
 
458  0 toggle public Node(int nodeType, Node left, Node mid, Node mid2, Node right,
459    int lineno, int charno) {
460  0 this(nodeType, left, mid, mid2, right);
461  0 sourcePosition = mergeLineCharNo(lineno, charno);
462    }
463   
 
464  0 toggle public Node(int nodeType, Node[] children, int lineno, int charno) {
465  0 this(nodeType, children);
466  0 sourcePosition = mergeLineCharNo(lineno, charno);
467    }
468   
 
469  0 toggle public Node(int nodeType, Node[] children) {
470  0 this.type = nodeType;
471  0 parent = null;
472  0 if (children.length != 0) {
473  0 this.first = children[0];
474  0 this.last = children[children.length - 1];
475   
476  0 for (int i = 1; i < children.length; i++) {
477  0 if (null != children[i - 1].next) {
478    // fail early on loops. implies same node in array twice
479  0 throw new IllegalArgumentException("duplicate child");
480    }
481  0 children[i - 1].next = children[i];
482  0 Preconditions.checkArgument(children[i - 1].parent == null);
483  0 children[i - 1].parent = this;
484    }
485  0 Preconditions.checkArgument(children[children.length - 1].parent == null);
486  0 children[children.length - 1].parent = this;
487   
488  0 if (null != this.last.next) {
489    // fail early on loops. implies same node in array twice
490  0 throw new IllegalArgumentException("duplicate child");
491    }
492    }
493    }
494   
 
495  27354 toggle public static Node newNumber(double number) {
496  27354 return new NumberNode(number);
497    }
498   
 
499  0 toggle public static Node newNumber(double number, int lineno, int charno) {
500  0 return new NumberNode(number, lineno, charno);
501    }
502   
 
503  9906 toggle public static Node newString(String str) {
504  9906 return new StringNode(Token.STRING, str);
505    }
506   
 
507  771188 toggle public static Node newString(int type, String str) {
508  771188 return new StringNode(type, str);
509    }
510   
 
511  8577 toggle public static Node newString(String str, int lineno, int charno) {
512  8577 return new StringNode(Token.STRING, str, lineno, charno);
513    }
514   
 
515  185 toggle public static Node newString(int type, String str, int lineno, int charno) {
516  185 return new StringNode(type, str, lineno, charno);
517    }
518   
 
519  13803755 toggle public int getType() {
520  13803755 return type;
521    }
522   
 
523  1641 toggle public void setType(int type) {
524  1641 this.type = type;
525    }
526   
 
527  108074 toggle public boolean hasChildren() {
528  108074 return first != null;
529    }
530   
 
531  4242989 toggle public Node getFirstChild() {
532  4242989 return first;
533    }
534   
 
535  1200528 toggle public Node getLastChild() {
536  1200528 return last;
537    }
538   
 
539  3386288 toggle public Node getNext() {
540  3386288 return next;
541    }
542   
 
543  12146 toggle public Node getChildBefore(Node child) {
544  12146 if (child == first) {
545  3503 return null;
546    }
547  8643 Node n = first;
548  10286 while (n.next != child) {
549  1643 n = n.next;
550  1643 if (n == null) {
551  0 throw new RuntimeException("node is not a child");
552    }
553    }
554  8643 return n;
555    }
556   
 
557  17104 toggle public Node getChildAtIndex(int i) {
558  17104 Node n = first;
559  34639 while (i > 0) {
560  17535 n = n.next;
561  17535 i--;
562    }
563  17104 return n;
564    }
565   
 
566  22 toggle public int getIndexOfChild(Node child) {
567  22 Node n = first;
568  22 int i = 0;
569  65 while (n != null) {
570  64 if (child == n) {
571  21 return i;
572    }
573   
574  43 n = n.next;
575  43 i++;
576    }
577  1 return -1;
578    }
579   
 
580  995 toggle public Node getLastSibling() {
581  995 Node n = this;
582  1916 while (n.next != null) {
583  921 n = n.next;
584    }
585  995 return n;
586    }
587   
 
588  1950 toggle public void addChildToFront(Node child) {
589  1950 Preconditions.checkArgument(child.parent == null);
590  1950 Preconditions.checkArgument(child.next == null);
591  1950 child.parent = this;
592  1950 child.next = first;
593  1950 first = child;
594  1950 if (last == null) {
595  1653 last = child;
596    }
597    }
598   
 
599  925738 toggle public void addChildToBack(Node child) {
600  925738 Preconditions.checkArgument(child.parent == null);
601  925738 Preconditions.checkArgument(child.next == null);
602  925738 child.parent = this;
603  925738 child.next = null;
604  925738 if (last == null) {
605  721351 first = last = child;
606  721351 return;
607    }
608  204387 last.next = child;
609  204387 last = child;
610    }
611   
 
612  178 toggle public void addChildrenToFront(Node children) {
613  413 for (Node child = children; child != null; child = child.next) {
614  235 Preconditions.checkArgument(child.parent == null);
615  235 child.parent = this;
616    }
617  178 Node lastSib = children.getLastSibling();
618  178 lastSib.next = first;
619  178 first = children;
620  178 if (last == null) {
621  127 last = lastSib;
622    }
623    }
624   
 
625  183 toggle public void addChildrenToBack(Node children) {
626  183 addChildrenAfter(children, getLastChild());
627    }
628   
629    /**
630    * Add 'child' before 'node'.
631    */
 
632  767 toggle public void addChildBefore(Node newChild, Node node) {
633  767 Preconditions.checkArgument(node != null && node.parent == this,
634    "The existing child node of the parent should not be null.");
635  767 Preconditions.checkArgument(newChild.next == null,
636    "The new child node has siblings.");
637  767 Preconditions.checkArgument(newChild.parent == null,
638    "The new child node already has a parent.");
639  767 if (first == node) {
640  435 newChild.parent = this;
641  435 newChild.next = first;
642  435 first = newChild;
643  435 return;
644    }
645  332 Node prev = getChildBefore(node);
646  332 addChildAfter(newChild, prev);
647    }
648   
649    /**
650    * Add 'child' after 'node'.
651    */
 
652  595 toggle public void addChildAfter(Node newChild, Node node) {
653  595 Preconditions.checkArgument(newChild.next == null,
654    "The new child node has siblings.");
655  595 addChildrenAfter(newChild, node);
656    }
657   
658    /**
659    * Add all children after 'node'.
660    */
 
661  791 toggle public void addChildrenAfter(Node children, Node node) {
662  791 Preconditions.checkArgument(node == null || node.parent == this);
663  2017 for (Node child = children; child != null; child = child.next) {
664  1226 Preconditions.checkArgument(child.parent == null);
665  1226 child.parent = this;
666    }
667   
668  791 Node lastSibling = children.getLastSibling();
669  791 if (node != null) {
670  768 Node oldNext = node.next;
671  768 node.next = children;
672  768 lastSibling.next = oldNext;
673  768 if (node == last) {
674  324 last = lastSibling;
675    }
676    } else {
677    // Append to the beginning.
678  23 if (first != null) {
679  0 lastSibling.next = first;
680    } else {
681  23 last = lastSibling;
682    }
683  23 first = children;
684    }
685    }
686   
687    /**
688    * Detach a child from its parent and siblings.
689    */
 
690  7983 toggle public void removeChild(Node child) {
691  7983 Node prev = getChildBefore(child);
692  7983 if (prev == null)
693  2903 first = first.next;
694    else
695  5080 prev.next = child.next;
696  6452 if (child == last) last = prev;
697  7983 child.next = null;
698  7983 child.parent = null;
699    }
700   
701    /**
702    * Detaches child from Node and replaces it with newChild.
703    */
 
704  11637 toggle public void replaceChild(Node child, Node newChild) {
705  11637 Preconditions.checkArgument(newChild.next == null,
706    "The new child node has siblings.");
707  11637 Preconditions.checkArgument(newChild.parent == null,
708    "The new child node already has a parent.");
709   
710    // Copy over important information.
711  11637 newChild.copyInformationFrom(child);
712   
713  11637 newChild.next = child.next;
714  11637 newChild.parent = this;
715  11637 if (child == first) {
716  8643 first = newChild;
717    } else {
718  2994 Node prev = getChildBefore(child);
719  2994 prev.next = newChild;
720    }
721  11637 if (child == last)
722  8834 last = newChild;
723  11637 child.next = null;
724  11637 child.parent = null;
725    }
726   
 
727  0 toggle public void replaceChildAfter(Node prevChild, Node newChild) {
728  0 Preconditions.checkArgument(prevChild.parent == this,
729    "prev is not a child of this node.");
730   
731  0 Preconditions.checkArgument(newChild.next == null,
732    "The new child node has siblings.");
733  0 Preconditions.checkArgument(newChild.parent == null,
734    "The new child node already has a parent.");
735   
736    // Copy over important information.
737  0 newChild.copyInformationFrom(prevChild);
738   
739  0 Node child = prevChild.next;
740  0 newChild.next = child.next;
741  0 newChild.parent = this;
742  0 prevChild.next = newChild;
743  0 if (child == last)
744  0 last = newChild;
745  0 child.next = null;
746  0 child.parent = null;
747    }
748   
 
749  1123351 toggle @VisibleForTesting
750    PropListItem lookupProperty(int propType) {
751  1123351 PropListItem x = propListHead;
752  1958988 while (x != null && propType != x.getType()) {
753  835637 x = x.getNext();
754    }
755  1123351 return x;
756    }
757   
758    /**
759    * Clone the properties from the provided node without copying
760    * the property object. The receiving node may not have any
761    * existing properties.
762    * @param other The node to clone properties from.
763    * @return this node.
764    */
 
765  346214 toggle public Node clonePropsFrom(Node other) {
766  346214 Preconditions.checkState(this.propListHead == null,
767    "Node has existing properties.");
768  346214 this.propListHead = other.propListHead;
769  346214 return this;
770    }
771   
 
772  922513 toggle public void removeProp(int propType) {
773  922513 PropListItem result = removeProp(propListHead, propType);
774  922513 if (result != propListHead) {
775  31318 propListHead = result;
776    }
777    }
778   
779    /**
780    * @param item The item to inspect
781    * @param propType The property to look for
782    * @return The replacement list if the property was removed, or
783    * 'item' otherwise.
784    */
 
785  1084300 toggle private PropListItem removeProp(PropListItem item, int propType) {
786  1084300 if (item == null) {
787  891195 return null;
788  193105 } else if (item.getType() == propType) {
789  31318 return item.getNext();
790    } else {
791  161787 PropListItem result = removeProp(item.getNext(), propType);
792  161787 if (result != item.getNext()) {
793  29722 return item.chain(result);
794    } else {
795  132065 return item;
796    }
797    }
798    }
799   
 
800  868647 toggle public Object getProp(int propType) {
801  868647 PropListItem item = lookupProperty(propType);
802  868647 if (item == null) {
803  369390 return null;
804    }
805  499257 return item.getObjectValue();
806    }
807   
 
808  204262 toggle public boolean getBooleanProp(int propType) {
809  204262 return getIntProp(propType) != 0;
810    }
811   
812    /**
813    * Returns the integer value for the property, or 0 if the property
814    * is not defined.
815    */
 
816  254365 toggle public int getIntProp(int propType) {
817  254365 PropListItem item = lookupProperty(propType);
818  254365 if (item == null) {
819  183988 return 0;
820    }
821  70377 return item.getIntValue();
822    }
823   
 
824  0 toggle public int getExistingIntProp(int propType) {
825  0 PropListItem item = lookupProperty(propType);
826  0 if (item == null) {
827  0 throw new IllegalStateException("missing prop: " + propType);
828    }
829  0 return item.getIntValue();
830    }
831   
 
832  154069 toggle public void putProp(int propType, Object value) {
833  154069 removeProp(propType);
834  154069 if (value != null) {
835  130877 propListHead = createProp(propType, value, propListHead);
836    }
837    }
838   
 
839  755117 toggle public void putBooleanProp(int propType, boolean value) {
840  755117 putIntProp(propType, value ? 1 : 0);
841    }
842   
 
843  768423 toggle public void putIntProp(int propType, int value) {
844  768423 removeProp(propType);
845  768423 if (value != 0) {
846  767604 propListHead = createProp(propType, value, propListHead);
847    }
848    }
849   
 
850  130877 toggle PropListItem createProp(int propType, Object value, PropListItem next) {
851  130877 return new ObjectPropListItem(propType, value, next);
852    }
853   
 
854  767604 toggle PropListItem createProp(int propType, int value, PropListItem next) {
855  767604 return new IntPropListItem(propType, value, next);
856    }
857   
858    // Gets all the property types, in sorted order.
 
859  314 toggle private int[] getSortedPropTypes() {
860  314 int count = 0;
861  653 for (PropListItem x = propListHead; x != null; x = x.getNext()) {
862  339 count++;
863    }
864   
865  314 int[] keys = new int[count];
866  653 for (PropListItem x = propListHead; x != null; x = x.getNext()) {
867  339 count--;
868  339 keys[count] = x.getType();
869    }
870   
871  314 Arrays.sort(keys);
872  314 return keys;
873    }
874   
875    /** Can only be called when <tt>getType() == TokenStream.NUMBER</tt> */
 
876  0 toggle public double getDouble() throws UnsupportedOperationException {
877  0 if (this.getType() == Token.NUMBER) {
878  0 throw new IllegalStateException(
879    "Number node not created with Node.newNumber");
880    } else {
881  0 throw new UnsupportedOperationException(this + " is not a number node");
882    }
883    }
884   
885    /** Can only be called when <tt>getType() == TokenStream.NUMBER</tt> */
 
886  0 toggle public void setDouble(double s) throws UnsupportedOperationException {
887  0 if (this.getType() == Token.NUMBER) {
888  0 throw new IllegalStateException(
889    "Number node not created with Node.newNumber");
890    } else {
891  0 throw new UnsupportedOperationException(this + " is not a string node");
892    }
893    }
894   
895    /** Can only be called when node has String context. */
 
896  0 toggle public String getString() throws UnsupportedOperationException {
897  0 if (this.getType() == Token.STRING) {
898  0 throw new IllegalStateException(
899    "String node not created with Node.newString");
900    } else {
901  0 throw new UnsupportedOperationException(this + " is not a string node");
902    }
903    }
904   
905    /** Can only be called when node has String context. */
 
906  0 toggle public void setString(String s) throws UnsupportedOperationException {
907  0 if (this.getType() == Token.STRING) {
908  0 throw new IllegalStateException(
909    "String node not created with Node.newString");
910    } else {
911  0 throw new UnsupportedOperationException(this + " is not a string node");
912    }
913    }
914   
 
915  314 toggle @Override
916    public String toString() {
917  314 return toString(true, true, true);
918    }
919   
 
920  333 toggle public String toString(
921    boolean printSource,
922    boolean printAnnotations,
923    boolean printType) {
924  333 StringBuilder sb = new StringBuilder();
925  333 toString(sb, printSource, printAnnotations, printType);
926  333 return sb.toString();
927    }
928   
 
929  333 toggle private void toString(
930    StringBuilder sb,
931    boolean printSource,
932    boolean printAnnotations,
933    boolean printType) {
934  333 sb.append(Token.name(type));
935  333 if (this instanceof StringNode) {
936  99 sb.append(' ');
937  99 sb.append(getString());
938  234 } else if (type == Token.FUNCTION) {
939  11 sb.append(' ');
940    // In the case of JsDoc trees, the first child is often not a string
941    // which causes exceptions to be thrown when calling toString or
942    // toStringTree.
943  11 if (first == null || first.getType() != Token.NAME) {
944  2 sb.append("<invalid>");
945    } else {
946  9 sb.append(first.getString());
947    }
948  223 } else if (type == Token.NUMBER) {
949  49 sb.append(' ');
950  49 sb.append(getDouble());
951    }
952  333 if (printSource) {
953  314 int lineno = getLineno();
954  314 if (lineno != -1) {
955  233 sb.append(' ');
956  233 sb.append(lineno);
957    }
958    }
959   
960  333 if (printAnnotations) {
961  314 int[] keys = getSortedPropTypes();
962  653 for (int i = 0; i < keys.length; i++) {
963  339 int type = keys[i];
964  339 PropListItem x = lookupProperty(type);
965  339 sb.append(" [");
966  339 sb.append(propToString(type));
967  339 sb.append(": ");
968  339 String value;
969  339 switch (type) {
970  339 default:
971  339 value = x.toString();
972  339 break;
973    }
974  339 sb.append(value);
975  339 sb.append(']');
976    }
977    }
978   
979  333 if (printType) {
980  314 if (jsType != null) {
981  12 String jsTypeString = jsType.toString();
982  12 if (jsTypeString != null) {
983  12 sb.append(" : ");
984  12 sb.append(jsTypeString);
985    }
986    }
987    }
988    }
989   
990   
 
991  56 toggle public String toStringTree() {
992  56 return toStringTreeImpl();
993    }
994   
 
995  56 toggle private String toStringTreeImpl() {
996  56 try {
997  56 StringBuilder s = new StringBuilder();
998  56 appendStringTree(s);
999  56 return s.toString();
1000    } catch (IOException e) {
1001  0 throw new RuntimeException("Should not happen\n" + e);
1002    }
1003    }
1004   
 
1005  56 toggle public void appendStringTree(Appendable appendable) throws IOException {
1006  56 toStringTreeHelper(this, 0, appendable);
1007    }
1008   
 
1009  276 toggle private static void toStringTreeHelper(Node n, int level, Appendable sb)
1010    throws IOException {
1011  817 for (int i = 0; i != level; ++i) {
1012  541 sb.append(" ");
1013    }
1014  276 sb.append(n.toString());
1015  276 sb.append('\n');
1016  276 for (Node cursor = n.getFirstChild();
1017  496 cursor != null;
1018    cursor = cursor.getNext()) {
1019  220 toStringTreeHelper(cursor, level + 1, sb);
1020    }
1021    }
1022   
1023    int type; // type of the node; Token.NAME for example
1024    Node next; // next sibling
1025    private Node first; // first element of a linked list of children
1026    private Node last; // last element of a linked list of children
1027   
1028    /**
1029    * Linked list of properties. Since vast majority of nodes would have
1030    * no more then 2 properties, linked list saves memory and provides
1031    * fast lookup. If this does not holds, propListHead can be replaced
1032    * by UintMap.
1033    */
1034    private PropListItem propListHead;
1035   
1036    /**
1037    * COLUMN_BITS represents how many of the lower-order bits of
1038    * sourcePosition are reserved for storing the column number.
1039    * Bits above these store the line number.
1040    * This gives us decent position information for everything except
1041    * files already passed through a minimizer, where lines might
1042    * be longer than 4096 characters.
1043    */
1044    public static final int COLUMN_BITS = 12;
1045   
1046    /**
1047    * MAX_COLUMN_NUMBER represents the maximum column number that can
1048    * be represented. JSCompiler's modifications to Rhino cause all
1049    * tokens located beyond the maximum column to MAX_COLUMN_NUMBER.
1050    */
1051    public static final int MAX_COLUMN_NUMBER = (1 << COLUMN_BITS) - 1;
1052   
1053    /**
1054    * COLUMN_MASK stores a value where bits storing the column number
1055    * are set, and bits storing the line are not set. It's handy for
1056    * separating column number from line number.
1057    */
1058    public static final int COLUMN_MASK = MAX_COLUMN_NUMBER;
1059   
1060    /**
1061    * Source position of this node. The position is encoded with the
1062    * column number in the low 12 bits of the integer, and the line
1063    * number in the rest. Create some handy constants so we can change this
1064    * size if we want.
1065    */
1066    private int sourcePosition;
1067   
1068    private JSType jsType;
1069   
1070    private Node parent;
1071   
1072    //==========================================================================
1073    // Source position management
1074   
 
1075  72705 toggle public void setStaticSourceFile(StaticSourceFile file) {
1076  72705 this.putProp(STATIC_SOURCE_FILE, file);
1077    }
1078   
1079    /** Sets the source file to a non-extern file of the given name. */
 
1080  10 toggle public void setSourceFileForTesting(String name) {
1081  10 this.putProp(STATIC_SOURCE_FILE, new SimpleSourceFile(name, false));
1082    }
1083   
 
1084  139859 toggle public String getSourceFileName() {
1085  139859 StaticSourceFile file = getStaticSourceFile();
1086  139859 return file == null ? null : file.getName();
1087    }
1088   
1089    /** Returns the source file associated with this input. May be null */
 
1090  196576 toggle public StaticSourceFile getStaticSourceFile() {
1091  196576 return ((StaticSourceFile) this.getProp(STATIC_SOURCE_FILE));
1092    }
1093   
1094    /**
1095    * @param inputId
1096    */
 
1097  29901 toggle public void setInputId(InputId inputId) {
1098  29901 this.putProp(INPUT_ID, inputId);
1099    }
1100   
1101    /**
1102    * @return The Id of the CompilerInput associated with this Node.
1103    */
 
1104  286633 toggle public InputId getInputId() {
1105  286633 return ((InputId) this.getProp(INPUT_ID));
1106    }
1107   
 
1108  14789 toggle public boolean isFromExterns() {
1109  14789 StaticSourceFile file = getStaticSourceFile();
1110  14789 return file == null ? false : file.isExtern();
1111    }
1112   
 
1113  5 toggle public int getLength() {
1114  5 return getIntProp(LENGTH);
1115    }
1116   
 
1117  12929 toggle public void setLength(int length) {
1118  12929 putIntProp(LENGTH, length);
1119    }
1120   
 
1121  772295 toggle public int getLineno() {
1122  772295 return extractLineno(sourcePosition);
1123    }
1124   
 
1125  379501 toggle public int getCharno() {
1126  379501 return extractCharno(sourcePosition);
1127    }
1128   
 
1129  2 toggle public int getSourceOffset() {
1130  2 StaticSourceFile file = getStaticSourceFile();
1131  2 if (file == null) {
1132  1 return -1;
1133    }
1134  1 int lineno = getLineno();
1135  1 if (lineno == -1) {
1136  1 return -1;
1137    }
1138  0 return file.getLineOffset(lineno) + getCharno();
1139    }
1140   
 
1141  72 toggle public int getSourcePosition() {
1142  72 return sourcePosition;
1143    }
1144   
 
1145  336271 toggle public void setLineno(int lineno) {
1146  336271 int charno = getCharno();
1147  336271 if (charno == -1) {
1148  336271 charno = 0;
1149    }
1150  336271 sourcePosition = mergeLineCharNo(lineno, charno);
1151    }
1152   
 
1153  334707 toggle public void setCharno(int charno) {
1154  334707 sourcePosition = mergeLineCharNo(getLineno(), charno);
1155    }
1156   
 
1157  11 toggle public void setSourceEncodedPosition(int sourcePosition) {
1158  11 this.sourcePosition = sourcePosition;
1159    }
1160   
 
1161  290 toggle public void setSourceEncodedPositionForTree(int sourcePosition) {
1162  290 this.sourcePosition = sourcePosition;
1163   
1164  290 for (Node child = getFirstChild();
1165  518 child != null; child = child.getNext()) {
1166  228 child.setSourceEncodedPositionForTree(sourcePosition);
1167    }
1168    }
1169   
1170    /**
1171    * Merges the line number and character number in one integer. The Character
1172    * number takes the first 12 bits and the line number takes the rest. If
1173    * the character number is greater than <code>2<sup>12</sup>-1</code> it is
1174    * adjusted to <code>2<sup>12</sup>-1</code>.
1175    */
 
1176  688622 toggle protected static int mergeLineCharNo(int lineno, int charno) {
1177  688622 if (lineno < 0 || charno < 0) {
1178  13714 return -1;
1179  674908 } else if ((charno & ~COLUMN_MASK) != 0) {
1180  1 return lineno << COLUMN_BITS | COLUMN_MASK;
1181    } else {
1182  674907 return lineno << COLUMN_BITS | (charno & COLUMN_MASK);
1183    }
1184    }
1185   
1186    /**
1187    * Extracts the line number and character number from a merged line char
1188    * number (see {@link #mergeLineCharNo(int, int)}).
1189    */
 
1190  772296 toggle protected static int extractLineno(int lineCharNo) {
1191  772296 if (lineCharNo == -1) {
1192  260619 return -1;
1193    } else {
1194  511677 return lineCharNo >>> COLUMN_BITS;
1195    }
1196    }
1197   
1198    /**
1199    * Extracts the character number and character number from a merged line
1200    * char number (see {@link #mergeLineCharNo(int, int)}).
1201    */
 
1202  379502 toggle protected static int extractCharno(int lineCharNo) {
1203  379502 if (lineCharNo == -1) {
1204  336277 return -1;
1205    } else {
1206  43225 return lineCharNo & COLUMN_MASK;
1207    }
1208    }
1209   
1210    //==========================================================================
1211    // Iteration
1212   
1213    /**
1214    * <p>Return an iterable object that iterates over this node's children.
1215    * The iterator does not support the optional operation
1216    * {@link Iterator#remove()}.</p>
1217    *
1218    * <p>To iterate over a node's siblings, one can write</p>
1219    * <pre>Node n = ...;
1220    * for (Node child : n.children()) { ...</pre>
1221    */
 
1222  22113 toggle public Iterable<Node> children() {
1223  22113 if (first == null) {
1224  8354 return Collections.emptySet();
1225    } else {
1226  13759 return new SiblingNodeIterable(first);
1227    }
1228    }
1229   
1230    /**
1231    * <p>Return an iterable object that iterates over this node's siblings.
1232    * The iterator does not support the optional operation
1233    * {@link Iterator#remove()}.</p>
1234    *
1235    * <p>To iterate over a node's siblings, one can write</p>
1236    * <pre>Node n = ...;
1237    * for (Node sibling : n.siblings()) { ...</pre>
1238    */
 
1239  17 toggle public Iterable<Node> siblings() {
1240  17 return new SiblingNodeIterable(this);
1241    }
1242   
1243    /**
1244    * @see Node#siblings()
1245    */
 
1246    private static final class SiblingNodeIterable
1247    implements Iterable<Node>, Iterator<Node> {
1248    private final Node start;
1249    private Node current;
1250    private boolean used;
1251   
 
1252  13776 toggle SiblingNodeIterable(Node start) {
1253  13776 this.start = start;
1254  13776 this.current = start;
1255  13776 this.used = false;
1256    }
1257   
 
1258  13773 toggle @Override
1259    public Iterator<Node> iterator() {
1260  13773 if (!used) {
1261  13773 used = true;
1262  13773 return this;
1263    } else {
1264    // We have already used the current object as an iterator;
1265    // we must create a new SiblingNodeIterable based on this
1266    // iterable's start node.
1267    //
1268    // Since the primary use case for Node.children is in for
1269    // loops, this branch is extremely unlikely.
1270  0 return (new SiblingNodeIterable(start)).iterator();
1271    }
1272    }
1273   
 
1274  30592 toggle @Override
1275    public boolean hasNext() {
1276  30592 return current != null;
1277    }
1278   
 
1279  18042 toggle @Override
1280    public Node next() {
1281  18042 if (current == null) {
1282  0 throw new NoSuchElementException();
1283    }
1284  18042 try {
1285  18042 return current;
1286    } finally {
1287  18042 current = current.getNext();
1288    }
1289    }
1290   
 
1291  0 toggle @Override
1292    public void remove() {
1293  0 throw new UnsupportedOperationException();
1294    }
1295    }
1296   
1297    // ==========================================================================
1298    // Accessors
1299   
 
1300  2 toggle PropListItem getPropListHeadForTesting() {
1301  2 return propListHead;
1302    }
1303   
 
1304  1183829 toggle public Node getParent() {
1305  1183829 return parent;
1306    }
1307   
1308    /**
1309    * Gets the ancestor node relative to this.
1310    *
1311    * @param level 0 = this, 1 = the parent, etc.
1312    */
 
1313  206 toggle public Node getAncestor(int level) {
1314  206 Preconditions.checkArgument(level >= 0);
1315  206 Node node = this;
1316  665 while (node != null && level-- > 0) {
1317  459 node = node.getParent();
1318    }
1319  206 return node;
1320    }
1321   
1322    /**
1323    * Iterates all of the node's ancestors excluding itself.
1324    */
 
1325  1035 toggle public AncestorIterable getAncestors() {
1326  1035 return new AncestorIterable(this.getParent());
1327    }
1328   
1329    /**
1330    * Iterator to go up the ancestor tree.
1331    */
 
1332    public static class AncestorIterable implements Iterable<Node> {
1333    private Node cur;
1334   
1335    /**
1336    * @param cur The node to start.
1337    */
 
1338  1035 toggle AncestorIterable(Node cur) {
1339  1035 this.cur = cur;
1340    }
1341   
 
1342  1035 toggle @Override
1343    public Iterator<Node> iterator() {
1344  1035 return new Iterator<Node>() {
 
1345  7513 toggle @Override
1346    public boolean hasNext() {
1347  7513 return cur != null;
1348    }
1349   
 
1350  3546 toggle @Override
1351    public Node next() {
1352  3546 if (!hasNext()) throw new NoSuchElementException();
1353  3546 Node n = cur;
1354  3546 cur = cur.getParent();
1355  3546 return n;
1356    }
1357   
 
1358  0 toggle @Override
1359    public void remove() {
1360  0 throw new UnsupportedOperationException();
1361    }
1362    };
1363    }
1364    }
1365   
1366    /**
1367    * Check for one child more efficiently than by iterating over all the
1368    * children as is done with Node.getChildCount().
1369    *
1370    * @return Whether the node has exactly one child.
1371    */
 
1372  56602 toggle public boolean hasOneChild() {
1373  56602 return first != null && first == last;
1374    }
1375   
1376    /**
1377    * Check for more than one child more efficiently than by iterating over all
1378    * the children as is done with Node.getChildCount().
1379    *
1380    * @return Whether the node more than one child.
1381    */
 
1382  15987 toggle public boolean hasMoreThanOneChild() {
1383  15987 return first != null && first != last;
1384    }
1385   
 
1386  1047767 toggle public int getChildCount() {
1387  1047767 int c = 0;
1388  2413092 for (Node n = first; n != null; n = n.next)
1389  1365325 c++;
1390   
1391  1047767 return c;
1392    }
1393   
1394    // Intended for testing and verification only.
 
1395  2204 toggle public boolean hasChild(Node child) {
1396  2204 for (Node n = first; n != null; n = n.getNext()) {
1397  2204 if (child == n) {
1398  2204 return true;
1399    }
1400    }
1401  0 return false;
1402    }
1403   
1404    /**
1405    * Checks if the subtree under this node is the same as another subtree.
1406    * Returns null if it's equal, or a message describing the differences.
1407    */
 
1408  9052 toggle public String checkTreeEquals(Node node2) {
1409  9052 NodeMismatch diff = checkTreeEqualsImpl(node2);
1410  9052 if (diff != null) {
1411  4 return "Node tree inequality:" +
1412    "\nTree1:\n" + toStringTree() +
1413    "\n\nTree2:\n" + node2.toStringTree() +
1414    "\n\nSubtree1: " + diff.nodeA.toStringTree() +
1415    "\n\nSubtree2: " + diff.nodeB.toStringTree();
1416    }
1417  9048 return null;
1418    }
1419   
1420    /**
1421    * Compare this node to node2 recursively and return the first pair of nodes
1422    * that differs doing a preorder depth-first traversal. Package private for
1423    * testing. Returns null if the nodes are equivalent.
1424    */
 
1425  162296 toggle NodeMismatch checkTreeEqualsImpl(Node node2) {
1426  162296 if (!isEquivalentTo(node2, false, false)) {
1427  7 return new NodeMismatch(this, node2);
1428    }
1429   
1430  162289 NodeMismatch res = null;
1431  162289 Node n, n2;
1432  162289 for (n = first, n2 = node2.first;
1433  315522 res == null && n != null;
1434    n = n.next, n2 = n2.next) {
1435  153241 if (node2 == null) {
1436  0 throw new IllegalStateException();
1437    }
1438  153241 res = n.checkTreeEqualsImpl(n2);
1439  153241 if (res != null) {
1440  8 return res;
1441    }
1442    }
1443  162281 return res;
1444    }
1445   
1446    /**
1447    * Compare this node to node2 recursively and return the first pair of nodes
1448    * that differs doing a preorder depth-first traversal. Package private for
1449    * testing. Returns null if the nodes are equivalent.
1450    */
 
1451  0 toggle NodeMismatch checkTreeTypeAwareEqualsImpl(Node node2) {
1452    // Do a non-recursive equivalents check.
1453  0 if (!isEquivalentTo(node2, true, false)) {
1454  0 return new NodeMismatch(this, node2);
1455    }
1456   
1457  0 NodeMismatch res = null;
1458  0 Node n, n2;
1459  0 for (n = first, n2 = node2.first;
1460  0 res == null && n != null;
1461    n = n.next, n2 = n2.next) {
1462  0 res = n.checkTreeTypeAwareEqualsImpl(n2);
1463  0 if (res != null) {
1464  0 return res;
1465    }
1466    }
1467  0 return res;
1468    }
1469   
1470    /** Returns true if this node is equivalent semantically to another */
 
1471  11774 toggle public boolean isEquivalentTo(Node node) {
1472  11774 return isEquivalentTo(node, false, true);
1473    }
1474   
1475    /**
1476    * Returns true if this node is equivalent semantically to another and
1477    * the types are equivalent.
1478    */
 
1479  8 toggle public boolean isEquivalentToTyped(Node node) {
1480  8 return isEquivalentTo(node, true, true);
1481    }
1482   
1483    /**
1484    * @param compareJsType Whether to compare the JSTypes of the nodes.
1485    * @param recurse Whether to compare the children of the current node, if
1486    * not only the the count of the children are compared.
1487    * @return Whether this node is equivalent semantically to the provided node.
1488    */
 
1489  239541 toggle boolean isEquivalentTo(Node node, boolean compareJsType, boolean recurse) {
1490  239541 if (type != node.getType()
1491    || getChildCount() != node.getChildCount()
1492    || this.getClass() != node.getClass()) {
1493  4815 return false;
1494    }
1495   
1496  234726 if (compareJsType && !JSType.isEquivalent(jsType, node.getJSType())) {
1497  3 return false;
1498    }
1499   
1500  234723 if (type == Token.INC || type == Token.DEC) {
1501  603 int post1 = this.getIntProp(INCRDECR_PROP);
1502  603 int post2 = node.getIntProp(INCRDECR_PROP);
1503  603 if (post1 != post2) {
1504  1 return false;
1505    }
1506  234120 } else if (type == Token.STRING || type == Token.STRING_KEY) {
1507  21311 if (type == Token.STRING_KEY) {
1508  843 int quoted1 = this.getIntProp(QUOTED_PROP);
1509  843 int quoted2 = node.getIntProp(QUOTED_PROP);
1510  843 if (quoted1 != quoted2) {
1511  1 return false;
1512    }
1513    }
1514   
1515  21310 int slashV1 = this.getIntProp(SLASH_V);
1516  21310 int slashV2 = node.getIntProp(SLASH_V);
1517  21310 if (slashV1 != slashV2) {
1518  1 return false;
1519    }
1520  212809 } else if (type == Token.CALL) {
1521  7186 if (this.getBooleanProp(FREE_CALL) != node.getBooleanProp(FREE_CALL)) {
1522  1 return false;
1523    }
1524    }
1525   
1526  234719 if (recurse) {
1527  72428 Node n, n2;
1528  72428 for (n = first, n2 = node.first;
1529  131014 n != null;
1530    n = n.next, n2 = n2.next) {
1531  65463 if (!n.isEquivalentTo(n2, compareJsType, true)) {
1532  6877 return false;
1533    }
1534    }
1535    }
1536   
1537  227842 return true;
1538    }
1539   
1540    /**
1541    * This function takes a set of GETPROP nodes and produces a string that is
1542    * each property separated by dots. If the node ultimately under the left
1543    * sub-tree is not a simple name, this is not a valid qualified name.
1544    *
1545    * @return a null if this is not a qualified name, or a dot-separated string
1546    * of the name and properties.
1547    */
 
1548  120006 toggle public String getQualifiedName() {
1549  120006 if (type == Token.NAME) {
1550  55034 String name = getString();
1551  55034 return name.isEmpty() ? null : name;
1552  64972 } else if (type == Token.GETPROP) {
1553  63211 String left = getFirstChild().getQualifiedName();
1554  63211 if (left == null) {
1555  385 return null;
1556    }
1557  62826 return left + "." + getLastChild().getString();
1558  1761 } else if (type == Token.THIS) {
1559  749 return "this";
1560    } else {
1561  1012 return null;
1562    }
1563    }
1564   
1565    /**
1566    * Returns whether a node corresponds to a simple or a qualified name, such as
1567    * <code>x</code> or <code>a.b.c</code> or <code>this.a</code>.
1568    */
 
1569  53260 toggle public boolean isQualifiedName() {
1570  53260 switch (getType()) {
1571  20680 case Token.NAME:
1572  20680 return getString().isEmpty() ? false : true;
1573  528 case Token.THIS:
1574  528 return true;
1575  23706 case Token.GETPROP:
1576  23706 return getFirstChild().isQualifiedName();
1577  8346 default:
1578  8346 return false;
1579    }
1580    }
1581   
1582    /**
1583    * Returns whether a node corresponds to a simple or a qualified name without
1584    * a "this" reference, such as <code>a.b.c</code>, but not <code>this.a</code>
1585    * .
1586    */
 
1587  2291 toggle public boolean isUnscopedQualifiedName() {
1588  2291 switch (getType()) {
1589  878 case Token.NAME:
1590  878 return getString().isEmpty() ? false : true;
1591  1292 case Token.GETPROP:
1592  1292 return getFirstChild().isUnscopedQualifiedName();
1593  121 default:
1594  121 return false;
1595    }
1596    }
1597   
1598    // ==========================================================================
1599    // Mutators
1600   
1601    /**
1602    * Removes this node from its parent. Equivalent to:
1603    * node.getParent().removeChild();
1604    */
 
1605  4869 toggle public Node detachFromParent() {
1606  4869 Preconditions.checkState(parent != null);
1607  4869 parent.removeChild(this);
1608  4869 return this;
1609    }
1610   
1611    /**
1612    * Removes the first child of Node. Equivalent to:
1613    * node.removeChild(node.getFirstChild());
1614    *
1615    * @return The removed Node.
1616    */
 
1617  1002 toggle public Node removeFirstChild() {
1618  1002 Node child = first;
1619  1002 if (child != null) {
1620  997 removeChild(child);
1621    }
1622  1002 return child;
1623    }
1624   
1625    /**
1626    * @return A Node that is the head of the list of children.
1627    */
 
1628  111 toggle public Node removeChildren() {
1629  111 Node children = first;
1630  793 for (Node child = first; child != null; child = child.getNext()) {
1631  682 child.parent = null;
1632    }
1633  111 first = null;
1634  111 last = null;
1635  111 return children;
1636    }
1637   
1638    /**
1639    * Removes all children from this node and isolates the children from each
1640    * other.
1641    */
 
1642  102 toggle public void detachChildren() {
1643  321 for (Node child = first; child != null;) {
1644  219 Node nextChild = child.getNext();
1645  219 child.parent = null;
1646  219 child.next = null;
1647  219 child = nextChild;
1648    }
1649  102 first = null;
1650  102 last = null;
1651    }
1652   
 
1653  106 toggle public Node removeChildAfter(Node prev) {
1654  106 Preconditions.checkArgument(prev.parent == this,
1655    "prev is not a child of this node.");
1656  106 Preconditions.checkArgument(prev.next != null,
1657    "no next sibling.");
1658   
1659  106 Node child = prev.next;
1660  106 prev.next = child.next;
1661  29 if (child == last) last = prev;
1662  106 child.next = null;
1663  106 child.parent = null;
1664  106 return child;
1665    }
1666   
1667    /**
1668    * @return A detached clone of the Node, specifically excluding its children.
1669    */
 
1670  211076 toggle public Node cloneNode() {
1671  211076 Node result;
1672  211076 try {
1673  211076 result = (Node) super.clone();
1674    // PropListItem lists are immutable and can be shared so there is no
1675    // need to clone them here.
1676  211076 result.next = null;
1677  211076 result.first = null;
1678  211076 result.last = null;
1679  211076 result.parent = null;
1680    } catch (CloneNotSupportedException e) {
1681  0 throw new RuntimeException(e.getMessage());
1682    }
1683  211076 return result;
1684    }
1685   
1686    /**
1687    * @return A detached clone of the Node and all its children.
1688    */
 
1689  210948 toggle public Node cloneTree() {
1690  210948 Node result = cloneNode();
1691  413095 for (Node n2 = getFirstChild(); n2 != null; n2 = n2.getNext()) {
1692  202147 Node n2clone = n2.cloneTree();
1693  202147 n2clone.parent = result;
1694  202147 if (result.last != null) {
1695  79785 result.last.next = n2clone;
1696    }
1697  202147 if (result.first == null) {
1698  122362 result.first = n2clone;
1699    }
1700  202147 result.last = n2clone;
1701    }
1702  210948 return result;
1703    }
1704   
1705    /**
1706    * Copies source file and name information from the other
1707    * node given to the current node. Used for maintaining
1708    * debug information across node append and remove operations.
1709    * @return this
1710    */
1711    // TODO(nicksantos): The semantics of this method are ill-defined. Delete it.
 
1712  17776 toggle public Node copyInformationFrom(Node other) {
1713  17776 if (getProp(ORIGINALNAME_PROP) == null) {
1714  17581 putProp(ORIGINALNAME_PROP, other.getProp(ORIGINALNAME_PROP));
1715    }
1716   
1717  17776 if (getProp(STATIC_SOURCE_FILE) == null) {
1718  9376 putProp(STATIC_SOURCE_FILE, other.getProp(STATIC_SOURCE_FILE));
1719  9376 sourcePosition = other.sourcePosition;
1720    }
1721   
1722  17776 return this;
1723    }
1724   
1725    /**
1726    * Copies source file and name information from the other node to the
1727    * entire tree rooted at this node.
1728    * @return this
1729    */
1730    // TODO(nicksantos): The semantics of this method are ill-defined. Delete it.
 
1731  5685 toggle public Node copyInformationFromForTree(Node other) {
1732  5685 copyInformationFrom(other);
1733  5685 for (Node child = getFirstChild();
1734  8395 child != null; child = child.getNext()) {
1735  2710 child.copyInformationFromForTree(other);
1736    }
1737   
1738  5685 return this;
1739    }
1740   
1741    /**
1742    * Overwrite all the source information in this node with
1743    * that of {@code other}.
1744    */
 
1745  5498 toggle public Node useSourceInfoFrom(Node other) {
1746  5498 putProp(ORIGINALNAME_PROP, other.getProp(ORIGINALNAME_PROP));
1747  5498 putProp(STATIC_SOURCE_FILE, other.getProp(STATIC_SOURCE_FILE));
1748  5498 sourcePosition = other.sourcePosition;
1749  5498 return this;
1750    }
1751   
 
1752  1802 toggle public Node srcref(Node other) {
1753  1802 return useSourceInfoFrom(other);
1754    }
1755   
1756    /**
1757    * Overwrite all the source information in this node and its subtree with
1758    * that of {@code other}.
1759    */
 
1760  3696 toggle public Node useSourceInfoFromForTree(Node other) {
1761  3696 useSourceInfoFrom(other);
1762  3696 for (Node child = getFirstChild();
1763  4079 child != null; child = child.getNext()) {
1764  383 child.useSourceInfoFromForTree(other);
1765    }
1766   
1767  3696 return this;
1768    }
1769   
 
1770  3305 toggle public Node srcrefTree(Node other) {
1771  3305 return useSourceInfoFromForTree(other);
1772    }
1773   
1774    /**
1775    * Overwrite all the source information in this node with
1776    * that of {@code other} iff the source info is missing.
1777    */
 
1778  2 toggle public Node useSourceInfoIfMissingFrom(Node other) {
1779  2 if (getProp(ORIGINALNAME_PROP) == null) {
1780  2 putProp(ORIGINALNAME_PROP, other.getProp(ORIGINALNAME_PROP));
1781    }
1782   
1783  2 if (getProp(STATIC_SOURCE_FILE) == null) {
1784  1 putProp(STATIC_SOURCE_FILE, other.getProp(STATIC_SOURCE_FILE));
1785  1 sourcePosition = other.sourcePosition;
1786    }
1787   
1788  2 return this;
1789    }
1790   
1791    /**
1792    * Overwrite all the source information in this node and its subtree with
1793    * that of {@code other} iff the source info is missing.
1794    */
 
1795  0 toggle public Node useSourceInfoIfMissingFromForTree(Node other) {
1796  0 useSourceInfoIfMissingFrom(other);
1797  0 for (Node child = getFirstChild();
1798  0 child != null; child = child.getNext()) {
1799  0 child.useSourceInfoIfMissingFromForTree(other);
1800    }
1801   
1802  0 return this;
1803    }
1804   
1805    //==========================================================================
1806    // Custom annotations
1807   
 
1808  224753 toggle public JSType getJSType() {
1809  224753 return jsType;
1810    }
1811   
 
1812  819019 toggle public void setJSType(JSType jsType) {
1813  819019 this.jsType = jsType;
1814    }
1815   
 
1816  29535 toggle public FileLevelJsDocBuilder getJsDocBuilderForNode() {
1817  29535 return new FileLevelJsDocBuilder();
1818    }
1819   
1820    /**
1821    * An inner class that provides back-door access to the license
1822    * property of the JSDocInfo property for this node. This is only
1823    * meant to be used for top-level script nodes where the
1824    * {@link com.google.javascript.jscomp.parsing.JsDocInfoParser} needs to
1825    * be able to append directly to the top-level node, not just the
1826    * current node.
1827    */
 
1828    public class FileLevelJsDocBuilder {
 
1829  10 toggle public void append(String fileLevelComment) {
1830  10 JSDocInfo jsDocInfo = getJSDocInfo();
1831  10 if (jsDocInfo == null) {
1832    // TODO(user): Is there a way to determine whether to
1833    // parse the JsDoc documentation from here?
1834  9 jsDocInfo = new JSDocInfo(false);
1835    }
1836  10 String license = jsDocInfo.getLicense();
1837  10 if (license == null) {
1838  9 license = "";
1839    }
1840  10 jsDocInfo.setLicense(license + fileLevelComment);
1841  10 setJSDocInfo(jsDocInfo);
1842    }
1843    }
1844   
1845    /**
1846    * Get the {@link JSDocInfo} attached to this node.
1847    * @return the information or {@code null} if no JSDoc is attached to this
1848    * node
1849    */
 
1850  311250 toggle public JSDocInfo getJSDocInfo() {
1851  311250 return (JSDocInfo) getProp(JSDOC_INFO_PROP);
1852    }
1853   
1854    /**
1855    * Sets the {@link JSDocInfo} attached to this node.
1856    */
 
1857  13040 toggle public Node setJSDocInfo(JSDocInfo info) {
1858  13040 putProp(JSDOC_INFO_PROP, info);
1859  13040 return this;
1860    }
1861   
1862    /**
1863    * Sets whether this node is a variable length argument node. This
1864    * method is meaningful only on {@link Token#NAME} nodes
1865    * used to define a {@link Token#FUNCTION}'s argument list.
1866    */
 
1867  494140 toggle public void setVarArgs(boolean varArgs) {
1868  494140 putBooleanProp(VAR_ARGS_NAME, varArgs);
1869    }
1870   
1871    /**
1872    * Returns whether this node is a variable length argument node. This
1873    * method's return value is meaningful only on {@link Token#NAME} nodes
1874    * used to define a {@link Token#FUNCTION}'s argument list.
1875    */
 
1876  12122 toggle public boolean isVarArgs() {
1877  12122 return getBooleanProp(VAR_ARGS_NAME);
1878    }
1879   
1880    /**
1881    * Sets whether this node is an optional argument node. This
1882    * method is meaningful only on {@link Token#NAME} nodes
1883    * used to define a {@link Token#FUNCTION}'s argument list.
1884    */
 
1885  167917 toggle public void setOptionalArg(boolean optionalArg) {
1886  167917 putBooleanProp(OPT_ARG_NAME, optionalArg);
1887    }
1888   
1889    /**
1890    * Returns whether this node is an optional argument node. This
1891    * method's return value is meaningful only on {@link Token#NAME} nodes
1892    * used to define a {@link Token#FUNCTION}'s argument list.
1893    */
 
1894  4677 toggle public boolean isOptionalArg() {
1895  4677 return getBooleanProp(OPT_ARG_NAME);
1896    }
1897   
1898    /**
1899    * Sets whether this is a synthetic block that should not be considered
1900    * a real source block.
1901    */
 
1902  84748 toggle public void setIsSyntheticBlock(boolean val) {
1903  84748 putBooleanProp(SYNTHETIC_BLOCK_PROP, val);
1904    }
1905   
1906    /**
1907    * Returns whether this is a synthetic block that should not be considered
1908    * a real source block.
1909    */
 
1910  9487 toggle public boolean isSyntheticBlock() {
1911  9487 return getBooleanProp(SYNTHETIC_BLOCK_PROP);
1912    }
1913   
1914    /**
1915    * Sets the ES5 directives on this node.
1916    */
 
1917  14 toggle public void setDirectives(Set<String> val) {
1918  14 putProp(DIRECTIVES, val);
1919    }
1920   
1921    /**
1922    * Returns the set of ES5 directives for this node.
1923    */
 
1924  378 toggle @SuppressWarnings("unchecked")
1925    public Set<String> getDirectives() {
1926  378 return (Set<String>) getProp(DIRECTIVES);
1927    }
1928   
1929    /**
1930    * Adds a warning to be suppressed. This is indistinguishable
1931    * from having a {@code @suppress} tag in the code.
1932    */
 
1933  5 toggle public void addSuppression(String warning) {
1934  5 if (getJSDocInfo() == null) {
1935  5 setJSDocInfo(new JSDocInfo(false));
1936    }
1937  5 getJSDocInfo().addSuppression(warning);
1938    }
1939   
1940    /**
1941    * Sets whether this is a synthetic block that should not be considered
1942    * a real source block.
1943    */
 
1944  192 toggle public void setWasEmptyNode(boolean val) {
1945  192 putBooleanProp(EMPTY_BLOCK, val);
1946    }
1947   
1948    /**
1949    * Returns whether this is a synthetic block that should not be considered
1950    * a real source block.
1951    */
 
1952  14 toggle public boolean wasEmptyNode() {
1953  14 return getBooleanProp(EMPTY_BLOCK);
1954    }
1955   
1956    // There are four values of interest:
1957    // global state changes
1958    // this state changes
1959    // arguments state changes
1960    // whether the call throws an exception
1961    // locality of the result
1962    // We want a value of 0 to mean "global state changes and
1963    // unknown locality of result".
1964   
1965    final public static int FLAG_GLOBAL_STATE_UNMODIFIED = 1;
1966    final public static int FLAG_THIS_UNMODIFIED = 2;
1967    final public static int FLAG_ARGUMENTS_UNMODIFIED = 4;
1968    final public static int FLAG_NO_THROWS = 8;
1969    final public static int FLAG_LOCAL_RESULTS = 16;
1970   
1971    final public static int SIDE_EFFECTS_FLAGS_MASK = 31;
1972   
1973    final public static int SIDE_EFFECTS_ALL = 0;
1974    final public static int NO_SIDE_EFFECTS =
1975    FLAG_GLOBAL_STATE_UNMODIFIED
1976    | FLAG_THIS_UNMODIFIED
1977    | FLAG_ARGUMENTS_UNMODIFIED
1978    | FLAG_NO_THROWS;
1979   
1980    /**
1981    * Marks this function or constructor call's side effect flags.
1982    * This property is only meaningful for {@link Token#CALL} and
1983    * {@link Token#NEW} nodes.
1984    */
 
1985  370 toggle public void setSideEffectFlags(int flags) {
1986  370 Preconditions.checkArgument(
1987    getType() == Token.CALL || getType() == Token.NEW,
1988    "setIsNoSideEffectsCall only supports CALL and NEW nodes, got " +
1989    Token.name(getType()));
1990   
1991  370 putIntProp(SIDE_EFFECT_FLAGS, flags);
1992    }
1993   
 
1994  0 toggle public void setSideEffectFlags(SideEffectFlags flags) {
1995  0 setSideEffectFlags(flags.valueOf());
1996    }
1997   
1998    /**
1999    * Returns the side effects flags for this node.
2000    */
 
2001  3519 toggle public int getSideEffectFlags() {
2002  3519 return getIntProp(SIDE_EFFECT_FLAGS);
2003    }
2004   
2005    /**
2006    * A helper class for getting and setting the side-effect flags.
2007    * @author johnlenz@google.com (John Lenz)
2008    */
 
2009    public static class SideEffectFlags {
2010    private int value = Node.SIDE_EFFECTS_ALL;
2011   
 
2012  333 toggle public SideEffectFlags() {
2013    }
2014   
 
2015  0 toggle public SideEffectFlags(int value) {
2016  0 this.value = value;
2017    }
2018   
 
2019  347 toggle public int valueOf() {
2020  347 return value;
2021    }
2022   
2023    /** All side-effect occur and the returned results are non-local. */
 
2024  0 toggle public void setAllFlags() {
2025  0 value = Node.SIDE_EFFECTS_ALL;
2026    }
2027   
2028    /** No side-effects occur and the returned results are local. */
 
2029  96 toggle public void clearAllFlags() {
2030  96 value = Node.NO_SIDE_EFFECTS | Node.FLAG_LOCAL_RESULTS;
2031    }
2032   
 
2033  83 toggle public boolean areAllFlagsSet() {
2034  83 return value == Node.SIDE_EFFECTS_ALL;
2035    }
2036   
2037    /**
2038    * Preserve the return result flag, but clear the others:
2039    * no global state change, no throws, no this change, no arguments change
2040    */
 
2041  2 toggle public void clearSideEffectFlags() {
2042  2 value |= Node.NO_SIDE_EFFECTS;
2043    }
2044   
 
2045  287 toggle public void setMutatesGlobalState() {
2046    // Modify global means everything must be assumed to be modified.
2047  287 removeFlag(Node.FLAG_GLOBAL_STATE_UNMODIFIED);
2048  287 removeFlag(Node.FLAG_ARGUMENTS_UNMODIFIED);
2049  287 removeFlag(Node.FLAG_THIS_UNMODIFIED);
2050    }
2051   
 
2052  256 toggle public void setThrows() {
2053  256 removeFlag(Node.FLAG_NO_THROWS);
2054    }
2055   
 
2056  11 toggle public void setMutatesThis() {
2057  11 removeFlag(Node.FLAG_THIS_UNMODIFIED);
2058    }
2059   
 
2060  1 toggle public void setMutatesArguments() {
2061  1 removeFlag(Node.FLAG_ARGUMENTS_UNMODIFIED);
2062    }
2063   
 
2064  273 toggle public void setReturnsTainted() {
2065  273 removeFlag(Node.FLAG_LOCAL_RESULTS);
2066    }
2067   
 
2068  1402 toggle private void removeFlag(int flag) {
2069  1402 value &= ~flag;
2070    }
2071    }
2072   
2073    /**
2074    * @return Whether the only side-effect is "modifies this"
2075    */
 
2076  446 toggle public boolean isOnlyModifiesThisCall() {
2077  446 return areBitFlagsSet(
2078    getSideEffectFlags() & Node.NO_SIDE_EFFECTS,
2079    Node.FLAG_GLOBAL_STATE_UNMODIFIED
2080    | Node.FLAG_ARGUMENTS_UNMODIFIED
2081    | Node.FLAG_NO_THROWS);
2082    }
2083   
2084    /**
2085    * Returns true if this node is a function or constructor call that
2086    * has no side effects.
2087    */
 
2088  3017 toggle public boolean isNoSideEffectsCall() {
2089  3017 return areBitFlagsSet(getSideEffectFlags(), NO_SIDE_EFFECTS);
2090    }
2091   
2092    /**
2093    * Returns true if this node is a function or constructor call that
2094    * returns a primitive or a local object (an object that has no other
2095    * references).
2096    */
 
2097  0 toggle public boolean isLocalResultCall() {
2098  0 return areBitFlagsSet(getSideEffectFlags(), FLAG_LOCAL_RESULTS);
2099    }
2100   
2101    /**
2102    * returns true if all the flags are set in value.
2103    */
 
2104  3463 toggle private boolean areBitFlagsSet(int value, int flags) {
2105  3463 return (value & flags) == flags;
2106    }
2107   
2108    /**
2109    * This should only be called for STRING nodes children of OBJECTLIT.
2110    */
 
2111  0 toggle public boolean isQuotedString() {
2112  0 return false;
2113    }
2114   
2115    /**
2116    * This should only be called for STRING nodes children of OBJECTLIT.
2117    */
 
2118  0 toggle public void setQuotedString() {
2119  0 throw new IllegalStateException("not a StringNode");
2120    }
2121   
 
2122    static class NodeMismatch {
2123    final Node nodeA;
2124    final Node nodeB;
2125   
 
2126  9 toggle NodeMismatch(Node nodeA, Node nodeB) {
2127  9 this.nodeA = nodeA;
2128  9 this.nodeB = nodeB;
2129    }
2130   
 
2131  2 toggle @Override
2132    public boolean equals(Object object) {
2133  2 if (object instanceof NodeMismatch) {
2134  2 NodeMismatch that = (NodeMismatch) object;
2135  2 return that.nodeA.equals(this.nodeA) && that.nodeB.equals(this.nodeB);
2136    }
2137  0 return false;
2138    }
2139   
 
2140  0 toggle @Override
2141    public int hashCode() {
2142  0 return Objects.hashCode(nodeA, nodeB);
2143    }
2144    }
2145   
2146   
2147    /*** AST type check methods ***/
2148   
 
2149  516 toggle public boolean isAdd() {
2150  516 return this.getType() == Token.ADD;
2151    }
2152   
 
2153  9202 toggle public boolean isAnd() {
2154  9202 return this.getType() == Token.AND;
2155    }
2156   
 
2157  317 toggle public boolean isArrayLit() {
2158  317 return this.getType() == Token.ARRAYLIT;
2159    }
2160   
 
2161  153517 toggle public boolean isAssign() {
2162  153517 return this.getType() == Token.ASSIGN;
2163    }
2164   
 
2165  24 toggle public boolean isAssignAdd() {
2166  24 return this.getType() == Token.ASSIGN_ADD;
2167    }
2168   
 
2169  636629 toggle public boolean isBlock() {
2170  636629 return this.getType() == Token.BLOCK;
2171    }
2172   
 
2173  12 toggle public boolean isBreak() {
2174  12 return this.getType() == Token.BREAK;
2175    }
2176   
 
2177  90894 toggle public boolean isCall() {
2178  90894 return this.getType() == Token.CALL;
2179    }
2180   
 
2181  74289 toggle public boolean isCase() {
2182  74289 return this.getType() == Token.CASE;
2183    }
2184   
 
2185  8302 toggle public boolean isCast() {
2186  8302 return this.getType() == Token.CAST;
2187    }
2188   
 
2189  4284 toggle public boolean isCatch() {
2190  4284 return this.getType() == Token.CATCH;
2191    }
2192   
 
2193  22033 toggle public boolean isComma() {
2194  22033 return this.getType() == Token.COMMA;
2195    }
2196   
 
2197  0 toggle public boolean isContinue() {
2198  0 return this.getType() == Token.CONTINUE;
2199    }
2200   
 
2201  44 toggle public boolean isDebugger() {
2202  44 return this.getType() == Token.DEBUGGER;
2203    }
2204   
 
2205  7936 toggle public boolean isDec() {
2206  7936 return this.getType() == Token.DEC;
2207    }
2208   
 
2209  201 toggle public boolean isDefaultCase() {
2210  201 return this.getType() == Token.DEFAULT_CASE;
2211    }
2212   
 
2213  2845 toggle public boolean isDelProp() {
2214  2845 return this.getType() == Token.DELPROP;
2215    }
2216   
 
2217  4830 toggle public boolean isDo() {
2218  4830 return this.getType() == Token.DO;
2219    }
2220   
 
2221  30107 toggle public boolean isEmpty() {
2222  30107 return this.getType() == Token.EMPTY;
2223    }
2224   
 
2225  155943 toggle public boolean isExprResult() {
2226  155943 return this.getType() == Token.EXPR_RESULT;
2227    }
2228   
 
2229  0 toggle public boolean isFalse() {
2230  0 return this.getType() == Token.FALSE;
2231    }
2232   
 
2233  12266 toggle public boolean isFor() {
2234  12266 return this.getType() == Token.FOR;
2235    }
2236   
 
2237  1805256 toggle public boolean isFunction() {
2238  1805256 return this.getType() == Token.FUNCTION;
2239    }
2240   
 
2241  1571 toggle public boolean isGetterDef() {
2242  1571 return this.getType() == Token.GETTER_DEF;
2243    }
2244   
 
2245  24664 toggle public boolean isGetElem() {
2246  24664 return this.getType() == Token.GETELEM;
2247    }
2248   
 
2249  298719 toggle public boolean isGetProp() {
2250  298719 return this.getType() == Token.GETPROP;
2251    }
2252   
 
2253  9207 toggle public boolean isHook() {
2254  9207 return this.getType() == Token.HOOK;
2255    }
2256   
 
2257  4706 toggle public boolean isIf() {
2258  4706 return this.getType() == Token.IF;
2259    }
2260   
 
2261  1010 toggle public boolean isIn() {
2262  1010 return this.getType() == Token.IN;
2263    }
2264   
 
2265  7990 toggle public boolean isInc() {
2266  7990 return this.getType() == Token.INC;
2267    }
2268   
 
2269  502 toggle public boolean isInstanceOf() {
2270  502 return this.getType() == Token.INSTANCEOF;
2271    }
2272   
 
2273  302341 toggle public boolean isLabel() {
2274  302341 return this.getType() == Token.LABEL;
2275    }
2276   
 
2277  1060 toggle public boolean isLabelName() {
2278  1060 return this.getType() == Token.LABEL_NAME;
2279    }
2280   
 
2281  912592 toggle public boolean isName() {
2282  912592 return this.getType() == Token.NAME;
2283    }
2284   
 
2285  19 toggle public boolean isNE() {
2286  19 return this.getType() == Token.NE;
2287    }
2288   
 
2289  26576 toggle public boolean isNew() {
2290  26576 return this.getType() == Token.NEW;
2291    }
2292   
 
2293  145 toggle public boolean isNot() {
2294  145 return this.getType() == Token.NOT;
2295    }
2296   
 
2297  8327 toggle public boolean isNull() {
2298  8327 return this.getType() == Token.NULL;
2299    }
2300   
 
2301  33478 toggle public boolean isNumber() {
2302  33478 return this.getType() == Token.NUMBER;
2303    }
2304   
 
2305  445213 toggle public boolean isObjectLit() {
2306  445213 return this.getType() == Token.OBJECTLIT;
2307    }
2308   
 
2309  9272 toggle public boolean isOr() {
2310  9272 return this.getType() == Token.OR;
2311    }
2312   
 
2313  97008 toggle public boolean isParamList() {
2314  97008 return this.getType() == Token.PARAM_LIST;
2315    }
2316   
 
2317  3953 toggle public boolean isRegExp() {
2318  3953 return this.getType() == Token.REGEXP;
2319    }
2320   
 
2321  24164 toggle public boolean isReturn() {
2322  24164 return this.getType() == Token.RETURN;
2323    }
2324   
 
2325  1450953 toggle public boolean isScript() {
2326  1450953 return this.getType() == Token.SCRIPT;
2327    }
2328   
 
2329  1402 toggle public boolean isSetterDef() {
2330  1402 return this.getType() == Token.SETTER_DEF;
2331    }
2332   
 
2333  96533 toggle public boolean isString() {
2334  96533 return this.getType() == Token.STRING;
2335    }
2336   
 
2337  89930 toggle public boolean isStringKey() {
2338  89930 return this.getType() == Token.STRING_KEY;
2339    }
2340   
 
2341  1953 toggle public boolean isSwitch() {
2342  1953 return this.getType() == Token.SWITCH;
2343    }
2344   
 
2345  6503 toggle public boolean isThis() {
2346  6503 return this.getType() == Token.THIS;
2347    }
2348   
 
2349  2020 toggle public boolean isThrow() {
2350  2020 return this.getType() == Token.THROW;
2351    }
2352   
 
2353  258 toggle public boolean isTrue() {
2354  258 return this.getType() == Token.TRUE;
2355    }
2356   
 
2357  9540 toggle public boolean isTry() {
2358  9540 return this.getType() == Token.TRY;
2359    }
2360   
 
2361  194 toggle public boolean isTypeOf() {
2362  194 return this.getType() == Token.TYPEOF;
2363    }
2364   
 
2365  267651 toggle public boolean isVar() {
2366  267651 return this.getType() == Token.VAR;
2367    }
2368   
 
2369  0 toggle public boolean isVoid() {
2370  0 return this.getType() == Token.VOID;
2371    }
2372   
 
2373  1959 toggle public boolean isWhile() {
2374  1959 return this.getType() == Token.WHILE;
2375    }
2376   
 
2377  1938 toggle public boolean isWith() {
2378  1938 return this.getType() == Token.WITH;
2379    }
2380    }